package com.net.xpay.core.service.impl;

import com.google.common.base.Strings;
import com.net.xpay.common.domain.notify.ChargeRecordNotifyRecord;
import com.net.xpay.common.domain.openapi.OpenApp;
import com.net.xpay.common.enums.notify.NotifyStatus;
import com.net.xpay.common.util.OpenApiSignatureUtil;
import com.net.xpay.core.constant.PoseidonErrorCode;
import com.net.common.exception.BusinessException;
import com.net.common.util.HttpClientUtil;
import com.net.common.util.SerializationUtil;
import com.net.xpay.common.manager.notify.ChargeRecordNotifyRecordManager;
import com.net.xpay.common.manager.openapi.OpenAppManager;
import com.net.xpay.core.service.ChargeRecordNotifyRecordService;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 86188
 */
@Slf4j
@Service
public class ChargeRecordNotifyRecordServiceImpl implements ChargeRecordNotifyRecordService {

    @Autowired
    private ChargeRecordNotifyRecordManager chargeRecordNotifyRecordManager;

    @Autowired
    private OpenAppManager openAppManager;

    @Override
    public void initiateNotify(Long id) {
        if (id == null){
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "id不能为空");
        }
        ChargeRecordNotifyRecord record = chargeRecordNotifyRecordManager.getById(id);
        if (record == null){
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "回调记录不存在");
        }
        if (record.getStatus().equals(NotifyStatus.INIT) || record.getStatus().equals(NotifyStatus.OK)){
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "回调记录状态异常");
        }
        if (record.getStatus().equals(NotifyStatus.DEAD)){
            record.setStatus(NotifyStatus.WAIT);
        }
        record.setNotifyCount(0);
        record.setNextNotifyTime(LocalDateTime.now());
        chargeRecordNotifyRecordManager.update(record);
    }

    @Override
    public void notifyChargeRecordNotifyRecord(ChargeRecordNotifyRecord record) {
        if (Strings.isNullOrEmpty(record.getNotifyUrl())) {
            return;
        }

        OpenApp openApp = openAppManager.getById(record.getAppId());

        String time = System.currentTimeMillis() + "";
        Map<String, String> params = new HashMap<>();
        params.put("appId", record.getAppId().toString());
        params.put("timestamp", time);
        params.put("data", record.getNotifyContent());
        String content = OpenApiSignatureUtil.getSignCheckContent(params);
        String sign = OpenApiSignatureUtil.rsaSign(content, openApp.getPrivateKey(), "UTF-8", "RSA2");

        List<NameValuePair> paramList = new ArrayList<>();
        NameValuePair appkey = new BasicNameValuePair("appId", record.getAppId().toString());
        paramList.add(appkey);
        NameValuePair timestamp = new BasicNameValuePair("timestamp", time);
        paramList.add(timestamp);
        NameValuePair signature = new BasicNameValuePair("sign", sign);
        paramList.add(signature);
        NameValuePair data = new BasicNameValuePair("data", record.getNotifyContent());
        paramList.add(data);

        String resp;
        try {
            HttpPost method = new HttpPost(record.getNotifyUrl());
            method.setEntity(new UrlEncodedFormEntity(paramList, "UTF-8"));
            log.info("notifyChargeRecordNotifyRecord|id={}|userId={}|appId={}|params={}", record.getImportBizNo(), record.getUserId(), record.getAppId(), SerializationUtil.obj2String(paramList));
            resp = HttpClientUtil.getInstance().executeAndGet(method, null, "UTF-8");
            log.info("notifyChargeRecordNotifyRecord|id={}|userId={}|appId={}|resp={}", record.getImportBizNo(), record.getUserId(), record.getAppId(), resp);
            if (resp != null  && (
                    "ok".equalsIgnoreCase(resp.trim())
                            || "\"ok\"".equalsIgnoreCase(resp.trim())
                            || "success".equalsIgnoreCase(resp.trim())
                            || "\"success\"".equalsIgnoreCase(resp.trim())
            )) {
                record.setStatus(NotifyStatus.OK);
                record.setNotifyCount(record.getNotifyCount() + 1);
                record.setEndTime(LocalDateTime.now());
                chargeRecordNotifyRecordManager.update(record);
            } else {
                record.setNotifyCount(record.getNotifyCount() + 1);
                if (record.getNotifyCount() >= 8) {
                    record.setStatus(NotifyStatus.DEAD);
                    record.setEndTime(LocalDateTime.now());
                    chargeRecordNotifyRecordManager.update(record);
                } else {
                    long[] minutes = new long[]{
                            2, 10, 10, 60, 120, 360, 900
                    };
                    record.setNextNotifyTime(record.getNextNotifyTime().plusMinutes(minutes[(record.getNotifyCount() - 1) % 7]));
                    chargeRecordNotifyRecordManager.update(record);
                }
            }
        } catch (Throwable e) {
            log.error("notifyChargeRecordNotifyRecord error|id={}|userId={}", record.getImportBizNo(), record.getUserId(), e);
            record.setNotifyCount(record.getNotifyCount() + 1);
            if (record.getNotifyCount() >= 8) {
                record.setStatus(NotifyStatus.DEAD);
                record.setEndTime(LocalDateTime.now());
                chargeRecordNotifyRecordManager.update(record);
            } else {
                long[] minutes = new long[]{
                        2, 10, 10, 60, 120, 360, 900
                };
                record.setNextNotifyTime(record.getNextNotifyTime().plusMinutes(minutes[(record.getNotifyCount() - 1) % 7]));
                chargeRecordNotifyRecordManager.update(record);
            }
        }


    }

}
